package com.fhzn.boss.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fhzn.boss.context.RequestContext;
import com.fhzn.boss.entity.Tag;
import com.fhzn.boss.entity.TagType;
import com.fhzn.boss.mapper.TagMapper;
import com.fhzn.boss.service.TagService;
import com.fhzn.boss.web.converter.TagConverter;
import com.fhzn.boss.web.request.DictQuery;
import com.fhzn.boss.web.vo.TagVO;
import com.fhzn.commons.toolkit.entity.PageRequest;
import com.fhzn.commons.toolkit.exception.BuzException;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 老顾
 * @apiNote
 * @since 2024/1/22
 */
@Service
@RequiredArgsConstructor
public class TagServiceImpl implements TagService {
    private final TagMapper tagMapper;

    @Override
    public Page<Tag> dictsWithPage(DictQuery query) {
        QueryWrapper<Tag> wrapper = assembleDictQuery(query);
        PageRequest page = query.getPage();
        return tagMapper.selectPage(Page.of(page.getPage(), page.getPageSize()), wrapper);
    }

    @Override
    public List<Tag> dicts(DictQuery query) {
        QueryWrapper<Tag> wrapper = assembleDictQuery(query);
        if (!Objects.isNull(query.getAppCode()) && !query.getAppCode().isEmpty()) {
            wrapper.eq("app_code", query.getAppCode());
        } else {
            wrapper.eq("app_code", "BOSS");
        }
        return tagMapper.selectList(wrapper);
    }

    @Override
    public Tag dict(String type, String code) {
        QueryWrapper<Tag> wrapper = Wrappers.<Tag>query().eq("type", type).eq("code", code).last("limit 1");
        return tagMapper.selectOne(wrapper);
    }

    private QueryWrapper<Tag> assembleDictQuery(DictQuery query) {
        QueryWrapper<Tag> wrapper = Wrappers.<Tag>query().eq("type", query.getType()).orderByAsc("sort").orderByDesc("id");
        if (!Objects.isNull(query.getName())) {
            wrapper.eq("name", query.getName());
        }
        if (!Objects.isNull(query.getParentId())) {
            wrapper.eq("parent_id", query.getParentId());
        }
        if (!Objects.isNull(query.getIfHidden())) {
            wrapper.eq("if_hidden", query.getIfHidden());
        }
        if (!query.getCodes().isEmpty()) {
            wrapper.in("code", query.getCodes());
        }
        return wrapper;
    }

    @Override
    public List<Tag> getWithSubTags(String type, Integer parentId) {
        QueryWrapper<Tag> wrapper = Wrappers.<Tag>query().eq("type", type).orderByAsc("sort").orderByDesc("id");
        List<Tag> list = tagMapper.selectList(wrapper);
        if (Objects.isNull(parentId) || Objects.equals(parentId, 0)) {
            return list;
        }
        List<Tag> ret = Lists.newArrayListWithCapacity(list.size());
        list.stream().filter(t -> Objects.equals(t.getId(), parentId)).forEach(ret::add);
        Map<Integer, List<Tag>> parentId2tags = list.stream().collect(Collectors.groupingBy(Tag::getParentId));
        Queue<Integer> parentIdQueue = new LinkedList<>();
        parentIdQueue.add(parentId);
        while (!parentIdQueue.isEmpty()) {
            Integer curId = parentIdQueue.poll();
            List<Tag> tmpTags = parentId2tags.get(curId);
            if (Objects.isNull(tmpTags) || tmpTags.isEmpty()) {
                continue;
            }
            for (Tag tmpTag : tmpTags) {
                parentIdQueue.add(tmpTag.getId());
                ret.add(tmpTag);
            }
        }
        return ret;
    }

    @Override
    public void delete(Integer id) {
        tagMapper.deleteById(id, RequestContext.getRequestData().getHandler());
    }

    @Override
    public Integer saveOrUpdateType(TagType type) {
        Tag tag = type.toTagType(type);
        return saveOrUpdate(tag);
    }

    @Override
    public Integer saveOrUpdate(Tag tag) {
        try {
            if (Objects.isNull(tag.getId())) {
                tagMapper.insert(tag);
            } else {
                tag.setModifier(RequestContext.getRequestData().getInvokeAppName());
                tagMapper.updateById(tag);
            }
        } catch (Exception e) {
            throw new BuzException("字典信息重复！");
        }
        return tag.getId();
    }

    @Override
    public Tag getById(Integer id) {
        return tagMapper.selectById(id);
    }

    @Override
    public List<TagType> dictsClassifyList() {
        return dicts(DictQuery.typeOf(TagType.PLATFORM_DICT_TYPE)).stream().map(TagType::fromTag).collect(Collectors.toList());
    }

    @Override
    public List<TagType> dictsClassifyAppCodeList(String appCode) {
        return dicts(DictQuery.typeOf(TagType.PLATFORM_DICT_TYPE).setAppCode(appCode)).stream().map(TagType::fromTag).collect(Collectors.toList());
    }

    @Override
    public List<TagType> dictsBuiltInAppCodeList(String appCode) {
        return dicts(DictQuery.typeOf(TagType.BUILT_IN_DICT_TYPE).setAppCode(appCode)).stream().map(TagType::fromTag).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void importPlatformDict(String data) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            JsonNode rootNode = objectMapper.readTree(data);
            JsonNode tagsNode = rootNode.get("tags");

            if (tagsNode.isArray()) {
                for (JsonNode tagNode : tagsNode) {
                    TagVO tagVO = objectMapper.treeToValue(tagNode, TagVO.class);
                    Tag tag = TagConverter.fromTagVO(tagVO);

                    // 检查数据库中是否已存在相同的记录
                    Tag existingTag = tagMapper.findByCodeAndAppCode(tag.getCode(), tag.getAppCode());
                    if (existingTag != null) {
                        // 如果存在，更新记录
                        tag.setId(existingTag.getId());
                        tagMapper.updateById(existingTag);
                    } else {
                        // 如果不存在，插入新记录
                        tagMapper.insert(tag);
                    }
                }
            }
        } catch (Exception e) {
            // 抛出异常时，可以提供更多的错误信息
            throw new BuzException("导入失败，字典信息处理出错");
        }
    }
}
